/**

Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016.  All rights reserved.

Contact:
     SYSTAP, LLC DBA Blazegraph
     2501 Calvert ST NW #106
     Washington, DC 20008
     licenses@blazegraph.com

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
/*
 * Created on Sep 4, 2011
 */

package com.bigdata.rdf.sparql.ast.eval;

import java.util.LinkedList;
import java.util.List;
import java.util.Properties;

import junit.framework.TestResult;
import junit.framework.TestSuite;

import com.bigdata.bop.BOpUtility;
import com.bigdata.bop.Constant;
import com.bigdata.bop.IBindingSet;
import com.bigdata.bop.IConstant;
import com.bigdata.bop.IVariable;
import com.bigdata.bop.PipelineOp;
import com.bigdata.bop.Var;
import com.bigdata.bop.bindingSet.ListBindingSet;
import com.bigdata.bop.engine.QueryEngine;
import com.bigdata.bop.fed.QueryEngineFactory;
import com.bigdata.bop.join.HashIndexOp;
import com.bigdata.bop.join.NestedLoopJoinOp;
import com.bigdata.bop.join.PipelineJoin;
import com.bigdata.bop.join.SolutionSetHashJoinOp;
import com.bigdata.bop.rdf.join.ChunkedMaterializationOp;
import com.bigdata.bop.solutions.ProjectionOp;
import com.bigdata.bop.solutions.SliceOp;
import com.bigdata.journal.BufferMode;
import com.bigdata.journal.IBTreeManager;
import com.bigdata.rdf.internal.impl.literal.XSDNumericIV;
import com.bigdata.rdf.model.BigdataLiteral;
import com.bigdata.rdf.model.BigdataURI;
import com.bigdata.rdf.model.BigdataValue;
import com.bigdata.rdf.model.BigdataValueFactory;
import com.bigdata.rdf.sparql.ast.ASTContainer;
import com.bigdata.rdf.sparql.ast.NamedSubqueryRoot;
import com.bigdata.rdf.sparql.ast.eval.TestTCK.TCKStressTests;
import com.bigdata.rdf.sparql.ast.ssets.ISolutionSetManager;
import com.bigdata.rdf.sparql.ast.ssets.SolutionSetManager;
import com.bigdata.rdf.store.AbstractTripleStore;
import com.bigdata.rwstore.IRWStrategy;
import com.bigdata.rwstore.sector.MemStore;

/**
 * Data driven test suite for INCLUDE of named solution sets NOT generated by a
 * {@link NamedSubqueryRoot}.  This test suite is examines several details,
 * including the ability to locate and join with a pre-existing named solution
 * set, the ability to deliver the named solution set in order
 * 
 * @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a>
 * @version $Id: TestNamedSubQuery.java 6080 2012-03-07 18:38:55Z thompsonbry $
 */
public class TestInclude extends AbstractDataDrivenSPARQLTestCase {

    /**
     *
     */
    public TestInclude() {
    }

    /**
     * @param name
     */
    public TestInclude(String name) {
        super(name);
    }
    
    /**
     * Overridden to force the use of the {@link MemStore} since the solution
     * set cache is only enabled for {@link IRWStrategy} instances.
     */
    @Override
    public Properties getProperties() {

        // Note: clone to avoid modifying!!!
        final Properties properties = (Properties) super.getProperties().clone();

        properties.setProperty(com.bigdata.journal.Options.BUFFER_MODE,
                BufferMode.MemStore.name());
        
        return properties;
        
    }

    protected <T> IConstant<T> asConst(final T val) {

        return new Constant<T>(val);
        
    }
    
    /**
	 * This test populates a named solution set and then examines the ability to
	 * deliver a SLICE of that named solution set in the same order in which the
	 * data were stored. Normally, the named solution set would be created using
	 * <code>INSERT INTO SOLUTIONS</code>, but in this case we drop down a level
	 * and handle the creation of the named solution set in the test setup.
	 * 
	 * <pre>
	 * SELECT ?x ?y WHERE { 
	 * 
	 *    # Turn off the join order optimizer.
	 *    hint:Query hint:optimizer "None" .
	 * 
	 *    # Run joins in the given order (INCLUDE is 2nd).
	 *    
	 *    # bind x => {Mike;Bryan}
	 *    ?x rdf:type foaf:Person .
	 *    
	 *    # join on (x) => {(x=Mike,y=2);(x=Bryan;y=4)} 
	 *    INCLUDE %solutionSet1 .
	 * 
	 * }
	 * </pre>
	 */
    public void test_include_02() throws Exception {

        final TestHelper testHelper = new TestHelper(
        		"include_02",// name
        		"include_02.rq",// query URL
        		"include_02.trig",// data URL
        		"include_02.srx",// results URL
        		true  // check order(!)
        		);

        final AbstractTripleStore tripleStore = testHelper.getTripleStore();
        
        final BigdataValueFactory vf = tripleStore.getValueFactory();
        
		final QueryEngine queryEngine = QueryEngineFactory.getInstance()
				.getQueryController(tripleStore.getIndexManager());
		
        final ISolutionSetManager sparqlCache = new SolutionSetManager(
                (IBTreeManager) queryEngine.getIndexManager(),
                tripleStore.getNamespace(), tripleStore.getTimestamp());

		final String solutionSet = "%solutionSet1";
		
        final IVariable<?> x = Var.var("x");
        final IVariable<?> y = Var.var("y");
        final IVariable<?> z = Var.var("z");
        
		final XSDNumericIV<BigdataLiteral> one = new XSDNumericIV<BigdataLiteral>(
				1);
		one.setValue(vf.createLiteral(1));
		
		final XSDNumericIV<BigdataLiteral> two = new XSDNumericIV<BigdataLiteral>(
				2);
//		two.setValue(vf.createLiteral(2));
		
		final XSDNumericIV<BigdataLiteral> three = new XSDNumericIV<BigdataLiteral>(
				3);
//		three.setValue(vf.createLiteral(3));
		
		final XSDNumericIV<BigdataLiteral> four = new XSDNumericIV<BigdataLiteral>(
				4);
		four.setValue(vf.createLiteral(4));
		
		final XSDNumericIV<BigdataLiteral> five = new XSDNumericIV<BigdataLiteral>(
				5);
		five.setValue(vf.createLiteral(5));
		
        final List<IBindingSet> bsets = new LinkedList<IBindingSet>();
        {
            final IBindingSet bset = new ListBindingSet();
            bset.set(x, asConst(one));
            bset.set(y, asConst(two));
            bsets.add(bset);
        }
        {
            final IBindingSet bset = new ListBindingSet();
            bsets.add(bset);
        }
        {
            final IBindingSet bset = new ListBindingSet();
            bset.set(x, asConst(three));
            bset.set(y, asConst(four));
            bset.set(z, asConst(five));
            bsets.add(bset);
        }

        final IBindingSet[] bindingSets = bsets.toArray(new IBindingSet[]{});

		sparqlCache.putSolutions(solutionSet,
				BOpUtility.asIterator(bindingSets));

        final ASTContainer astContainer = testHelper.runTest();

        final PipelineOp queryPlan = astContainer.getQueryPlan();
        
        // top level should be the SLICE operator.
        assertTrue(queryPlan instanceof SliceOp);

        // sole argument should be the PROJECTION operator.
        final PipelineOp projectionOp = (PipelineOp) queryPlan.get(0);

        assertTrue(projectionOp instanceof ProjectionOp);

        // sole argument should be the INCLUDE operator.
        final PipelineOp includeOp = (PipelineOp) projectionOp.get(0);
        
        // the INCLUDE should be evaluated using a solution set SCAN.
        assertTrue(includeOp instanceof NestedLoopJoinOp);
        
    }

    /**
     * A unit test for an INCLUDE with another JOIN. For this test, the INCLUDE
     * will run first:
     * 
     * <pre>
     * %solutionSet1::
     * {x=:Mike,  y=2}
     * {x=:Bryan, y=4}
     * {x=:DC,    y=1}
     * </pre>
     * 
     * <pre>
     * prefix : <http://www.bigdata.com/> 
     * prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> 
     * prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> 
     * prefix foaf: <http://xmlns.com/foaf/0.1/> 
     * 
     * SELECT ?x ?y WHERE { 
     * 
     *    # Turn off the join order optimizer.
     *    hint:Query hint:optimizer "None" .
     * 
     *    # Run joins in the given order (INCLUDE is 1st).
     *    
     *    # SCAN => {(x=Mike,y=2);(x=Bryan;y=4);(x=DC,y=1)} 
     *    INCLUDE %solutionSet1 .
     * 
     *    # JOIN on (x) => {(x=Mike,y=2);(x=Bryan,y=4)}
     *    ?x rdf:type foaf:Person .
     *    
     * }
     * </pre>
     * 
     * Note: This excercises the code path in {@link AST2BOpUtility} where we do
     * a SCAN on the named solution set for the INCLUDE and then join with the
     * access path.
     * 
     * @see #test_include_03()
     * 
     * @see <a href="https://sourceforge.net/apps/trac/bigdata/ticket/531" >
     *      SPARQL UPDATE for NAMED SOLUTION SETS </a>
     */
    public void test_include_03a() throws Exception {
        
        final TestHelper testHelper = new TestHelper(
                "include_03a",// name
                "include_03a.rq",// query URL
                "include_03.trig",// data URL
                "include_03.srx",// results URL
                false // check order
                );

        final AbstractTripleStore tripleStore = testHelper.getTripleStore();
        
        final BigdataValueFactory vf = tripleStore.getValueFactory();
        
        final QueryEngine queryEngine = QueryEngineFactory.getInstance()
                .getQueryController(tripleStore.getIndexManager());
        
        final ISolutionSetManager sparqlCache = new SolutionSetManager(
                (IBTreeManager) queryEngine.getIndexManager(),
                tripleStore.getNamespace(), tripleStore.getTimestamp());

        final String solutionSet = "%solutionSet1";
        
        final IVariable<?> x = Var.var("x");
        final IVariable<?> y = Var.var("y");

        // Resolve terms pre-loaded into the kb.
        final BigdataURI Mike = vf.createURI("http://www.bigdata.com/Mike"); 
        final BigdataURI Bryan = vf.createURI("http://www.bigdata.com/Bryan");
        final BigdataURI DC = vf.createURI("http://www.bigdata.com/DC");
        {
            tripleStore.addTerms(new BigdataValue[] { Mike, Bryan, DC });
            assertNotNull(Mike.getIV());
            assertNotNull(Bryan.getIV());
            assertNotNull(DC.getIV());
        }

        final XSDNumericIV<BigdataLiteral> one = new XSDNumericIV<BigdataLiteral>(
                1);
        one.setValue(vf.createLiteral(1));
        
        final XSDNumericIV<BigdataLiteral> two = new XSDNumericIV<BigdataLiteral>(
                2);
        two.setValue(vf.createLiteral(2));
        
//      final XSDNumericIV<BigdataLiteral> three = new XSDNumericIV<BigdataLiteral>(
//              3);
//      three.setValue(vf.createLiteral(3));
        
        final XSDNumericIV<BigdataLiteral> four = new XSDNumericIV<BigdataLiteral>(
                4);
        four.setValue(vf.createLiteral(4));
        
//      final XSDNumericIV<BigdataLiteral> five = new XSDNumericIV<BigdataLiteral>(
//              5);
//      five.setValue(vf.createLiteral(5));
        
        final List<IBindingSet> bsets = new LinkedList<IBindingSet>();
        {
            final IBindingSet bset = new ListBindingSet();
            bset.set(x, asConst(Mike.getIV()));
            bset.set(y, asConst(two));
            bsets.add(bset);
        }
        {
            final IBindingSet bset = new ListBindingSet();
            bset.set(x, asConst(Bryan.getIV()));
            bset.set(y, asConst(four));
            bsets.add(bset);
        }
        {
            final IBindingSet bset = new ListBindingSet();
            bset.set(x, asConst(DC.getIV()));
            bset.set(y, asConst(one));
            bsets.add(bset);
        }

        final IBindingSet[] bindingSets = bsets.toArray(new IBindingSet[]{});

        sparqlCache.putSolutions(solutionSet,
                BOpUtility.asIterator(bindingSets));

        final ASTContainer astContainer = testHelper.runTest();

        final PipelineOp queryPlan = astContainer.getQueryPlan();

        // top level should be chunked materialization operator
        assertTrue(queryPlan instanceof ChunkedMaterializationOp);
        
        // top level should be the PROJECTION operator.
        final PipelineOp projectionOp = (PipelineOp) queryPlan.get(0);
        assertTrue(projectionOp instanceof ProjectionOp);

        // sole argument should be the PIPELINE JOIN operator.
        final PipelineOp joinOp = (PipelineOp) projectionOp.get(0);
        assertTrue(joinOp instanceof PipelineJoin);

        /*
         * The sole argument of JOIN should be the INCLUDE operator, which
         * should be evaluated using a solution set SCAN. This is where we start
         * evaluation for this query.
         */
        final PipelineOp includeOp = (PipelineOp) joinOp.get(0);
        assertTrue(includeOp instanceof NestedLoopJoinOp);

    }

    /**
     * A unit test for an INCLUDE which is NOT the first JOIN in the WHERE
     * clause. This condition is enforced by turning off the join order
     * optimizer for this query.
     * <p>
     * Note: Since there is another JOIN in this query, there is no longer any
     * order guarantee for the resulting solutions.
     * 
     * <pre>
     * %solutionSet1::
     * {x=:Mike,  y=2}
     * {x=:Bryan, y=4}
     * {x=:DC,    y=1}
     * </pre>
     * 
     * <pre>
     * prefix : <http://www.bigdata.com/> 
     * prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> 
     * prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> 
     * prefix foaf: <http://xmlns.com/foaf/0.1/> 
     * 
     * SELECT ?x ?y WHERE { 
     * 
     *    # Turn off the join order optimizer.
     *    hint:Query hint:optimizer "None" .
     * 
     *    # Run joins in the given order (INCLUDE is 2nd).
     *    
     *    # bind x => {Mike;Bryan}
     *    ?x rdf:type foaf:Person .
     *    
     *    # join on (x) => {(x=Mike,y=2);(x=Bryan;y=4)} 
     *    INCLUDE %solutionSet1 .
     * 
     * }
     * </pre>
     * 
     * @see #test_include_03a()
     * 
     * @see <a href="https://sourceforge.net/apps/trac/bigdata/ticket/531" >
     *      SPARQL UPDATE for NAMED SOLUTION SETS </a>
     */
    public void test_include_03() throws Exception {
    	
        final TestHelper testHelper = new TestHelper(
        		"include_03",// name
        		"include_03.rq",// query URL
        		"include_03.trig",// data URL
        		"include_03.srx",// results URL
        		false // check order
        		);

        final AbstractTripleStore tripleStore = testHelper.getTripleStore();
        
        final BigdataValueFactory vf = tripleStore.getValueFactory();
        
		final QueryEngine queryEngine = QueryEngineFactory.getInstance()
				.getQueryController(tripleStore.getIndexManager());
		
        final ISolutionSetManager sparqlCache = new SolutionSetManager(
                (IBTreeManager) queryEngine.getIndexManager(),
                tripleStore.getNamespace(), tripleStore.getTimestamp());

		final String solutionSet = "%solutionSet1";
		
        final IVariable<?> x = Var.var("x");
        final IVariable<?> y = Var.var("y");

        // Resolve terms pre-loaded into the kb.
        final BigdataURI Mike = vf.createURI("http://www.bigdata.com/Mike"); 
        final BigdataURI Bryan = vf.createURI("http://www.bigdata.com/Bryan");
        final BigdataURI DC = vf.createURI("http://www.bigdata.com/DC");
		{
			tripleStore.addTerms(new BigdataValue[] { Mike, Bryan, DC });
			assertNotNull(Mike.getIV());
			assertNotNull(Bryan.getIV());
			assertNotNull(DC.getIV());
		}

		final XSDNumericIV<BigdataLiteral> one = new XSDNumericIV<BigdataLiteral>(
				1);
		one.setValue(vf.createLiteral(1));
		
		final XSDNumericIV<BigdataLiteral> two = new XSDNumericIV<BigdataLiteral>(
				2);
		two.setValue(vf.createLiteral(2));
		
//		final XSDNumericIV<BigdataLiteral> three = new XSDNumericIV<BigdataLiteral>(
//				3);
//		three.setValue(vf.createLiteral(3));
		
		final XSDNumericIV<BigdataLiteral> four = new XSDNumericIV<BigdataLiteral>(
				4);
		four.setValue(vf.createLiteral(4));
		
//		final XSDNumericIV<BigdataLiteral> five = new XSDNumericIV<BigdataLiteral>(
//				5);
//		five.setValue(vf.createLiteral(5));
		
		        /**
         * <pre>
         * %solutionSet1::
         * {x=:Mike,  y=2}
         * {x=:Bryan, y=4}
         * {x=:DC,    y=1}
         * </pre>
         */
        final List<IBindingSet> bsets = new LinkedList<IBindingSet>();
        {
            final IBindingSet bset = new ListBindingSet();
            bset.set(x, asConst(Mike.getIV()));
            bset.set(y, asConst(two));
            bsets.add(bset);
        }
        {
            final IBindingSet bset = new ListBindingSet();
            bset.set(x, asConst(Bryan.getIV()));
            bset.set(y, asConst(four));
            bsets.add(bset);
        }
        {
            final IBindingSet bset = new ListBindingSet();
            bset.set(x, asConst(DC.getIV()));
            bset.set(y, asConst(one));
            bsets.add(bset);
        }

        final IBindingSet[] bindingSets = bsets.toArray(new IBindingSet[]{});

		sparqlCache.putSolutions(solutionSet,
				BOpUtility.asIterator(bindingSets));

        final ASTContainer astContainer = testHelper.runTest();

        /**
         * The plan should be:
         * 
         * 1. A PipelineJoin for the initial triple pattern
         * 
         * 2. A HashIndexOp to generate an appropriate index for the join with
         * the solution set. (The main point of this test is to verify that we
         * build an appropriate hash index to do the join rather than using a
         * NestedLoopJoinOp.)
         * 
         * 3. A SolutionSetHashJoin
         * 
         * 4. A ProjectionOp.
         */
//        com.bigdata.bop.solutions.ProjectionOp[6](JVMSolutionSetHashJoinOp[5])[ com.bigdata.bop.BOp.bopId=6, com.bigdata.bop.BOp.evaluationContext=CONTROLLER, com.bigdata.bop.PipelineOp.sharedState=true, com.bigdata.bop.join.JoinAnnotations.select=[x, y], com.bigdata.bop.engine.QueryEngine.queryId=562dbadb-afcc-4a2c-bf70-2486f1061dc3]
//                com.bigdata.bop.join.JVMSolutionSetHashJoinOp[5](JVMHashIndexOp[4])[ com.bigdata.bop.BOp.bopId=5, com.bigdata.bop.BOp.evaluationContext=CONTROLLER, com.bigdata.bop.PipelineOp.sharedState=true, namedSetRef=NamedSolutionSetRef{queryId=562dbadb-afcc-4a2c-bf70-2486f1061dc3,namedSet=%solutionSet1,joinVars=[x]}, com.bigdata.bop.join.JoinAnnotations.constraints=null, class com.bigdata.bop.join.SolutionSetHashJoinOp.release=false]
//                  com.bigdata.bop.join.JVMHashIndexOp[4](PipelineJoin[3])[ com.bigdata.bop.BOp.bopId=4, com.bigdata.bop.BOp.evaluationContext=CONTROLLER, com.bigdata.bop.PipelineOp.maxParallel=1, com.bigdata.bop.PipelineOp.lastPass=true, com.bigdata.bop.PipelineOp.sharedState=true, com.bigdata.bop.join.JoinAnnotations.joinType=Normal, com.bigdata.bop.join.HashJoinAnnotations.joinVars=[x], com.bigdata.bop.join.JoinAnnotations.select=null, namedSetSourceRef=NamedSolutionSetRef{queryId=562dbadb-afcc-4a2c-bf70-2486f1061dc3,namedSet=%solutionSet1,joinVars=[]}, namedSetRef=NamedSolutionSetRef{queryId=562dbadb-afcc-4a2c-bf70-2486f1061dc3,namedSet=%solutionSet1,joinVars=[x]}]
//                    com.bigdata.bop.join.PipelineJoin[3]()[ com.bigdata.bop.BOp.bopId=3, com.bigdata.bop.join.JoinAnnotations.constraints=null, com.bigdata.bop.BOp.evaluationContext=ANY, com.bigdata.bop.join.AccessPathJoinAnnotations.predicate=SPOPredicate[1]]

        final PipelineOp queryPlan = astContainer.getQueryPlan();

        // top level should be chunked materialization operator
        assertTrue(queryPlan instanceof ChunkedMaterializationOp);
        
        // top level should be the PROJECTION operator.
        assertTrue(queryPlan.get(0) instanceof ProjectionOp);

        // sole argument should be the SOLUTION SET HASH JOIN operator.
        final PipelineOp solutionSetHashJoinOp = (PipelineOp) queryPlan.get(0).get(0);

        assertTrue(solutionSetHashJoinOp instanceof SolutionSetHashJoinOp);

        // sole argument should be the HASH INDEX BUILD operator.
        final PipelineOp hashIndexOp = (PipelineOp) solutionSetHashJoinOp.get(0);
        
        assertTrue(hashIndexOp instanceof HashIndexOp);

        // sole argument should be the PIPELINE JOIN (triple pattern).
        final PipelineOp pipelineJoinOp = (PipelineOp) hashIndexOp.get(0);

        assertTrue(pipelineJoinOp instanceof PipelineJoin);

    }
    
    /**
     * Execute the stress tests a couple of times.
     * 
     * @throws Exception
     */
    public void test_stressTests() throws Exception {

        for (int i = 0; i < 100; i++) {
            final TestSuite suite = new TestSuite(
                IncludeStressTests.class.getSimpleName());

            suite.addTestSuite(IncludeStressTests.class);
            suite.run(new TestResult());
        }
    }
    
    
    /**
     * Tests to be executed in a stress test fashion, i.e. multiple times.
     * 
     * @author msc
     */
    public static class IncludeStressTests 
    extends AbstractDataDrivenSPARQLTestCase  {
       
       
        /**
         * 
         */
        public IncludeStressTests() {
        }

        /**
         * @param name
         */
        public IncludeStressTests(String name) {
            super(name);
        }       
       
        /**
         * This test populates a named solution set and then examines the ability to
         * deliver that named solution set in the same order in which the data were
         * stored. Normally, the named solution set would be created using
         * <code>INSERT INTO SOLUTIONS</code>, but in this case we drop down a level
         * and handle the creation of the named solution set in the test setup.
         * 
         * <pre>
         * SELECT * WHERE { INCLUDE %solutionSet1 }
         * </pre>
         */
        public void test_include_01() throws Exception {

            final TestHelper testHelper = new TestHelper("include_01",// name
                "include_01.rq",// query URL
                "include_01.trig",// data URL
                "include_01.srx",// results URL
                true // check order(!)
            );

            final AbstractTripleStore tripleStore = testHelper.getTripleStore();

            final BigdataValueFactory vf = tripleStore.getValueFactory();

            final QueryEngine queryEngine = QueryEngineFactory.getInstance()
                .getQueryController(tripleStore.getIndexManager());

            final ISolutionSetManager sparqlCache = new SolutionSetManager(
                (IBTreeManager) queryEngine.getIndexManager(),
                tripleStore.getNamespace(), tripleStore.getTimestamp());

            final String solutionSet = "%solutionSet1";

            final IVariable<?> x = Var.var("x");
            final IVariable<?> y = Var.var("y");
            final IVariable<?> z = Var.var("z");

            final XSDNumericIV<BigdataLiteral> one = 
                new XSDNumericIV<BigdataLiteral>(1);
            one.setValue(vf.createLiteral(1));

            final XSDNumericIV<BigdataLiteral> two = 
                new XSDNumericIV<BigdataLiteral>(2);

            final XSDNumericIV<BigdataLiteral> three = 
                new XSDNumericIV<BigdataLiteral>(3);

            final XSDNumericIV<BigdataLiteral> four = 
                new XSDNumericIV<BigdataLiteral>(4);
            four.setValue(vf.createLiteral(4));

           final XSDNumericIV<BigdataLiteral> five = 
                new XSDNumericIV<BigdataLiteral>(5);
           five.setValue(vf.createLiteral(5));

           final List<IBindingSet> bsets = new LinkedList<IBindingSet>();
           {
                final IBindingSet bset = new ListBindingSet();
                bset.set(x, asConst(one));
                bset.set(y, asConst(two));
                bsets.add(bset);
           }

           {
               final IBindingSet bset = new ListBindingSet();
               bsets.add(bset);
           }
           
           {
               final IBindingSet bset = new ListBindingSet();
               bset.set(x, asConst(three));
               bset.set(y, asConst(four));
               bset.set(z, asConst(five));
               bsets.add(bset);
           }

           final IBindingSet[] bindingSets = bsets.toArray(new IBindingSet[] {});

           sparqlCache.putSolutions(solutionSet,
           BOpUtility.asIterator(bindingSets));

           final ASTContainer astContainer = testHelper.runTest();

           final PipelineOp queryPlan = astContainer.getQueryPlan();

           // top level should be the PROJECTION operator.
           assertTrue(queryPlan instanceof ProjectionOp);

           // sole argument should be the INCLUDE operator.
           final PipelineOp includeOp = (PipelineOp) queryPlan.get(0);

           // the INCLUDE should be evaluated using a solution set SCAN.
           assertTrue(includeOp instanceof NestedLoopJoinOp);

      }

      protected <T> IConstant<T> asConst(final T val) {

         return new Constant<T>(val);

      }
    }   
    
}
